import fs from 'fs'
import crypto from 'crypto'
import bcrypt from 'bcrypt'
import consola from 'consola'
import NodeRSA from 'node-rsa'
import { dateFormat } from '../tool'
import authConfig from '../../config/auth'
import {
  env,
  certDirectory,
  publicKeyName,
  privateKeyName
} from '../../config/commonConfig'

const auth = authConfig[env]

let privateKey

export const loadKey = file => {
  return fs.readFileSync(file, 'utf8')
}

export const generateKey = () => {
  let _resolve
  let _reject
  const readyPromise = new Promise((resolve, reject) => {
    _resolve = resolve
    _reject = _reject
  })
  const key = new NodeRSA({ b: 512 })

  key.setOptions({ encryptionScheme: 'pkcs1' })

  const privatePem = key.exportKey('pkcs1-private-pem')
  const publicDer = key.exportKey('pkcs8-public-der').toString('base64')
  try {
    fs.existsSync(certDirectory) || fs.mkdirSync(certDirectory)
    fs.writeFile(`${certDirectory}/${publicKeyName}`, publicDer, err => {
      if (err) throw err
      consola.success({
        message: `创建公钥成功！`,
        badge: true
      })
    })

    fs.writeFile(`${certDirectory}/${privateKeyName}`, privatePem, err => {
      if (err) throw err
      consola.success({
        message: `创建私钥成功！`,
        badge: true
      })
    })
    _resolve()
  } catch (error) {
    _reject(error)
  }
  return readyPromise
}

export const rsaDecrypt = str => {
  if (!privateKey) {
    privateKey = loadKey(`${certDirectory}/${privateKeyName}`)
  }
  let buffer = Buffer.from(str, 'base64')
  let decrypted = crypto.privateDecrypt(
    {
      key: privateKey,
      padding: crypto.constants.RSA_PKCS1_PADDING
    },
    buffer
  )
  return decrypted.toString()
}

export const rsaEncrypt = str => {
  if (!privateKey) {
    privateKey = loadKey(`${certDirectory}/${privateKeyName}`)
  }
  let encrypted = crypto.privateEncrypt(privateKey, Buffer.from(str, 'utf8'))
  return encrypted.toString('base64')
}

export const encryptPassword = pwd => {
  return bcrypt.hash(pwd, 8)
}

export const comparePassword = (pwd, hash) => {
  return bcrypt.compare(pwd, hash)
}

/**
 * @aes256加密模块
 * @param str string 要加密的字符串
 * @param secret string 要使用的加密密钥
 * @retrun string 加密后的字符串
 * */
export const getEncrypt = str => {
  const { key, iv } = auth
  const cipher = crypto.createCipher('aes-256-cbc', key, iv) //设置加密类型 和 要使用的加密密钥
  let enc = cipher.update(str, 'utf8', 'base64') //编码方式从utf-8转为base64
  enc += cipher.final('base64') //编码方式从转为base64
  return formatBase64(enc) //返回加密后的字符串
}
/**
 * @aes256解密模块
 * @param str string 要解密的字符串
 * @param secret string 要使用的解密密钥(要和密码的加密密钥对应,不然就解不了密啦)
 * @retrun string 解密后的字符串
 * */
export const getDecrypt = str => {
  const { key, iv } = auth
  const decipher = crypto.createDecipher('aes-256-cbc', key, iv)
  let dec = decipher.update(trimBase64(str), 'base64', 'utf8') //编码方式从base64转为utf-8;
  dec += decipher.final('utf8') //编码方式从utf-8;
  return dec
}

const formatBase64 = str => {
  return str.replace(
    /(\S{22})(={1,2})/g,
    ($0, $1, $2) => `qy${$1}${dateFormat('yyyyMMdd')}${$2}`
  )
}

const trimBase64 = str => {
  return str.replace(/qy(\S{22})\d*(={1,2})/g, ($0, $1, $2) => `${$1}${$2}`)
}
